home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CD ROM Paradise Collection 4
/
CD ROM Paradise Collection 4 1995 Nov.iso
/
program
/
tjgold.zip
/
INSTALL.004
/
FGUSER14.TXT
< prev
next >
Wrap
Text File
|
1995-05-29
|
47KB
|
1,147 lines
Displaying Lists in Windows
"He shall live and unto him shall
be given of the gold of Arabia."
1662 Prayer Book
Introduction
List, list, lists. Our lives and our software are often
dominated by lists. Gold provides a family of flexible tools to
help you manage software lists. (Your lives are your own
responsibility!)
In the last chapter you learned how data can be stored in
single and double linked lists. In this chapter you will learn how
the data in linked lists, as well as data stored in arrays and
databases, can be displayed in list windows.
Gold provides the following three categories of list window:
Category Description
Quick List Windows Many applications just want to pop-up a
simple (single column) list window and
allow the user to select one item. Gold
provides a simple but not very
customizable function RunListStrLL for
displaying quick and dirty lists.
Browse Windows As the name suggests, a browse window is
for browsing the contents of a list.
Unlike the other list catagories, a browse
window does not have a highlight bar --
there is no notion of a selected line or
item. The window can be scrolled
vertically and horizontally. Browse
windows are ideal for displaying file
contents, help text and the like.
List Windows List windows display data in single or
multiple columns, and one item in the list
is always highlighted, i.e. selected.The
user can (if the application permits it)
tag multiple items in the list. These
lists are ideal for displaying filenames,
or any list where the user needs to select
one (or more) items.
Grid Windows A grid window is similar to a list window
in as much as the user is presented with a
list and one item in the list is always
highlighted. A grid window is designed,
however, to provide a table or columnar
view of a record similar to the table
views in Paradox. A user can scroll right
and left one column at a time (as opposed
to one character at a time).
In addition to providing list windows, Gold supports all these
list types in user input forms, i.e. you can have a field on a form
which is a browser, list or grid. These features are discussed in
Chapter 16.
Quick and Dirty List Windows
In the remainder of this chapter you will learn how to use the
RunBrowse, RunList and RunGrid procedures to create flexible
windows with a myriad of options. Before you explore these
inticacies, you might want to consider using RunListStrLL (defined
below) for your simple list windows.
RunListStrLL(ListSource:StringLL;Tit:StrScreen):longint;
Displays the contents of a stringLL in a list window. The
function returns the number of the highlighted pick, or zero if the
user escapes.
This function uses the ListVars variables WX1, WY1, WX2, WY2
and WStyle to determine the window coordinates. Sets these
variables to appropriate values if the default window size is too
large.
Run the demo file DEMLIS5.PAS to see RunListStrLL in action.
Building a Flexible List Window -- A Crash Course
No matter which type of list you are displaying, Gold needs to
know the main properties of the data and the characteristics of the
window in which the data will be displayed. For example, before a
list window can be displayed, Gold needs to know some of the
following information:
What type of data is to be displayed, e.g. a single linked
list, double linked list, array, etc.
Where the data is stored, i.e. the name of the variable.
The dimensions and style of the window.
The window title.
Any optional list headers and footers.
What colors are to be used.
Can the user tag more than one item.
.... you get the idea.
You define all these list characteristics by creating a
variable (of type ListCfg, for list configuration), initializing
the variable, and then setting various components of the variable
to define your specific needs.
In other words, to display a list in a window you need at
least two variables: a list configuration variable, and a variable
used to store the data.
The following code (extracted from the demo file DEMLS1.PAS)
shows a minimalist application which displays the contents of
SingleLL in a list window:
var
Properties: ListCfg;
GirlFriends: SingleLL;
RetCode: integer;
procedure BuildTheList;
{}
begin
InitSLLStr(GirlFriends);
SLLSetActiveList(GirlFriends);
Retcode := SLLAddStr('Erica');
inc(Retcode,SLLAddStr('Theresa'));
inc(Retcode,SLLAddStr('Lynn'));
inc(Retcode,SLLAddStr('Donna'));
inc(Retcode,SLLAddStr('Godzilla'));
end; { BuildTheList }
procedure SetScreen;
{Paints the background}
begin
Clear(WhiteOnBlack,'°');
ClearLine(1,YellowOnBlue);
WriteCenter(1,UseTint,' A Simple List Window ');
GotoXY(1,1);
end; {SetScreen}
begin
BuildTheList;
SetScreen;
if RetCode <> 0 then
PromptOK(' Error ','Unable to build the list')
else
begin
InitListCfg(Properties);
ListAssignSLL(Properties,Girlfriends);
MouseShow(true);
RunList(Properties,' My first list! ');
MouseShow(false);
end;
SLLSetActiveList(GirlFriends);
SLLDestroy;
end. { DEMLS1 }
In this example, the list configuration variable is named
Properties, and the data is stored in a single linked list named
Girlfriends. (If you are not familiar with linked lists, read the
previous chapter before proceeding.)
Apart from the code to paint the screen and populate the
linked list, the list window can be displayed in just three lines
of code:
InitListCfg(Properties);
Uses InitListCfg to initialize the Properties variable to
default values.
ListAssignSLL(Properties,Girlfriends);
Uses ListAssignSLL to advise Properties of the data type
(SingleLL) and location (the address of the variable Girlfriends)
of the list data.
RunList(Properties,' My first list! ');
Calls RunList to display the list in a window.
If you run DEMOLS1.PAS you will see that Gold creates a large
list window. Since we didn't define any of the window properties,
apart from the window title (in the call to RunList), Gold used
some defaults.
You can refine the list window in many ways. The following
code fragment is an extract from DEMLS2.PAS which is the same code
base as DEMLS1.PAS except that the window is customized to better
fit the list of girlfriends!
ListSetWin(Properties,25,5,55,11,1);
Defining the List Configuration
The key to displaying list/browse/grid windows is to declare a
variable of type ListCfg, and then call Gold functions to set
ListCfg to meet your specific needs.
Initializing ListCfg
Always, always, always call InitListCfg to initialize the
ListCfg variable before calling the other list procedures and
functions.
InitListCFG(var ListDetails: ListCfg);
Initializes a list configuration variable.
Assigning the Data Source
Having initialized the ListCfg variable (I promise I won't
repeat the fact that it must be initialized) you then need to
update the variable with information about the list data source.
Gold can display the contents of a SingleLL, DoubleLL, array or a
custom data source where you supply a function to feed the list
engine with the necessary strings. Depending on your data source,
you would call one of the following procedures to update the
ListCfg variable with the data source details:
ListAssignSLL(var ListDetails: ListCfg; var TheList:SingleLL);
Sets the ListCfg variable data source as a single linked list
stored in the variable TheList.
ListAssignDLL(var ListDetails: ListCfg; var TheList:DoubleLL);
Sets the ListCfg variable data source as a double linked list
stored in the variable TheList.
ListAssignArray(var ListDetails: ListCfg; var ListSource;
StrLen:Byte;ArrayElements:byte);
Sets the ListCfg variable data source as a string array stored
in the variable ListSource. The last two parameters define the
length of each string in the array, and the number of elements in
the array, respectively.
The ListAssignCustom procedure is discussed later in the
section Using a Custom Data Source.
Setting Window Properties
When the ListCfg variable is initialized, the window
properties (such as the window position and dimensions) are set to
some standard defaults. If these defaults are not appropriate, you
can customize them with the following two procedures:
ListSetWin(var ListDetails: ListCfg; X1,Y1,X2,Y2:integer;
Style:byte);
Defines the upper left and lower right corners of the window
along with the window style. (Refer to Chapter 4 for a discussion
of window styles.)
ListSetGaps(var ListDetails:ListCfg;LeftGap,RightGap,
BotGap,TopGap: byte);
This procedure allows you to set the gap or whitespace area
around the list body. The list/browse/grid data does not need to
fill the entire window.
If you want to change the window defaults, update the
following variables: ListVars.X1, ListVars.Y1, ListVars.X2,
ListVars.Y2, and ListVars.WinStyle.
Multi-Column Lists
A list window displayed with RunList (but not RunBrowse or
RunGrid) can display a list in multiple columns. By default, a list
is displayed in a single column that is the width of the window,
but the following function can be used to change the default column
width to a fixed value:
ListSetColWidth(var ListDetails: ListCfg; Width: byte);
Specifies the width of each column in the list (when the list
is displayed with RunList).
If the column width is set to zero, or the specified column
width is wider than the window, Gold will display the list in a
single column.
Setting the Window Colors
As always, the default colors are defined in the TINT
structure, and the following elements pertain to list windows:
ListHi1
ListHi2
ListNorm1
ListNorm2
ListMarkers
ListScrollbarHi
ListScrollbarNorm
ListBorder1
ListBorder2
ListBorderOff
ListTitle
ListHeaders
ListIcons
You can modify the defaults (used by any new list windows
initialized after the modification) by using the standard
GoldSetColor procedure.
You can modify the colors of a specific list window by using
the following function:
ListSetColor(var ListDetails: ListCfg; A:TintElement; C:byte);
Sets the color of one of the elements of a list window.
The following code is an extract from DEMLS3.PAS which
customizes the list display colors:
procedure CustomizeColors;
{}
begin
ListSetColor(Prop,ListHi1,BlackonGreen);
ListSetColor(Prop,ListHi2,YellowOnGreen);
ListSetColor(Prop,ListNorm1,YellowOnMagenta);
ListSetColor(Prop,ListNorm2,WhiteOnMagenta);
ListSetColor(Prop,ListMarkers,LightgrayonMagenta);
ListSetColor(Prop,ListScrollbarHi,WhiteOnMagenta);
ListSetColor(Prop,ListScrollbarNorm,WhiteOnMagenta);
ListSetColor(Prop,ListBorder1,YellowOnMagenta);
ListSetColor(Prop,ListBorder2,YellowOnMagenta);
ListSetColor(Prop,ListBorderOff,BlackOnMagenta);
ListSetColor(Prop,ListTitle,WhiteOnMagenta);
ListSetColor(Prop,ListHeaders,GreenOnMagenta);
ListSetColor(Prop,ListIcons,LightCyanOnMagenta);
end; { CustomizeColors }
Controlling Item Tagging
List and grid windows (but not browse windows) support item
tagging whereby a user can select or tag more than one item in a
list. You might use this for marking items in a database to print,
or tag files to be deleted, etc.
Tagging is only supported in lists that have a data source of
SingleLL or DoubleLL.
By default a list does not support tagging. However, you can
use the following procedure to control tagging:
ListSetTagging(var ListDetails: ListCfg; On:boolean);
Sets the taggability state of a list or grid. Pass a TRUE to
allow tagging and a FALSE to disable it.
When an item is tagged, Gold accesses the appropriate node of
the list and updates one of the bit flags. The Gold constant TagBit
identifies the bit flag that is set when the item is tagged.
When the user has completed the tagging operation, you can use
the function SLLGetBit or DLLGetBit to test the bit status of each
item in the list.
The demo file DEMLS4.PAS displays a list of taggable files in
a multiple column window. The following code fragment is extracted
from DEMLS4.PAS and shows how to test whether the items in the list
are tagged:
for I := 1 to Properties.TotalNodes do
begin
if DLLGetBit(DLLNodePtr(I),TagBit) then
begin
writeln(DLLGetStr(I));
inc(Counter);
end;
end;
Notice that the ListCfg element TotalNodes is used to
determine how many nodes were displayed in the list window, i.e.
Properties.TotalNodes.
Dual Colored Lists
SingleLL- and DoubleLL-based lists support dual colored lists,
i.e. some items are displayed in one color and other items are
displayed in a different color. To enable dual colored lists, use
the following function:
ListSetTwoColors(var ListDetails: ListCfg; On:boolean);
Pass TRUE to enable two colored lists, or FALSE for single
colored lists.
Having enabled the two colors, you need to mark those items in
the list that you want displayed in the secondary color. Gold
checks the bit named ColBit at the node to decide which color set
to use. To force a node to be displayed in a secondary color, you
need to set the ColBit on.
The following code is an extract from DEMBR4.PAS which
displays lines that contain the words procedure and function in the
secondary color.
NodePtr := DLL.StartNodePtr;
while NodePtr <> nil do
begin
TempStr := DLLGetNodeStr(NodePtr,0,0);
if CaseSens then
P := pos(Str,TempStr)
else
P := pos(SetUpper(Str),SetUpper(TempStr));
if P > 0 then
DLLSetBit(NodePtr,Colbit,true);
NodePtr := NodePtr^.NextPtr;
end;
If you want to synchronize the tag and color features so that
all tagged items appear in a different color, Gold will do the work
for you. All you have to do is use the following procedure:
ListSetTagColor(var ListDetails: ListCfg; On:boolean);
Pass TRUE to have tagged items appear in the secondary color,
or FALSE to have tagged and untagged items appear in the same
color.
Using Headers and Footers
All three list window types (browse, list and grid) support
multi-line headers and footers. Out of the box, Gold limits the
number of heading lines and footer lines to 4, but you can change
the number by assigning a different value to the constants
ListMaxHeaders and ListMaxFooters declared in GOLDLIST.
To minimize memory usage, all headers and footers must be
stored as string variables in your program. (Gold simply stores a
pointer to the variable.)
The following six procedures can be used to manage the headers
and footers:
ListAssignHeader(var ListDetails: ListCfg; Line:byte; var
Heading:string);
Sets the list configuration variable to display a string as a
header. A string variable must be passed -- a string literal will
not be accepted. The line must be a value in the range 1 to
ListMaxHeaders (which defaults to 4).
ListAssignFooter(var ListDetails: ListCfg; Line:byte; var
Footnote:string);
Sets the list configuration variable to display a string as a
footer. A string variable must be passed -- a string literal will
not be accepted. The line must be a value in the range 1 to
ListMaxFooters (which defaults to 4).
ListSetHeaderOff(var ListDetails: ListCfg; Line:byte);
Removes a header line which was previously assigned with
ListAssignHeader.
ListSetFooterOff(var ListDetails: ListCfg; Line:byte);
Removes a header line which was previously assigned with
ListAssignFooter.
ListScrollHeader(var ListDetails: ListCfg; On:boolean);
Pass TRUE if the headings should be scrolled right and left
when the user scrolls the list body right and left, or FALSE if the
header should remain fixed.
ListScrollFooter(var ListDetails: ListCfg; On:boolean);
Pass TRUE if the headings should be scrolled right and left
when the user scrolls the list body right and left, or FALSE if the
header should remain fixed.
You can automatically canter a header or footer by prefixing
the string with the ^ character.
The following code is an extract from the demo file DEMLS5.PAS
which shows how to add headers and footers to a list window:
InitListCfg(Settings);
ListAssignDLL(Settings,DLL);
ListSetWin(Settings,1,2,80,24,1);
ListSetTwoColors(Settings,True);
Header1 := 'This is a header';
Header2 := 'This is a second header';
Footer := 'This is a footer';
ListAssignHeader(Settings,1,Header1);
ListAssignHeader(Settings,2,Header2);
ListAssignFooter(Settings,1,Footer);
CursorOff;
RunBrowse(Settings,' Browsing '+FileName);
CursorOn;
Refer to the section Displaying Grid Windows for more
information on setting headers from grid windows.
Displaying Browse Windows
Browse windows are designed for displaying lists without a
highlight bar. Browse windows are ideal for displaying the contents
of text files, and displaying help text.
Browsing Files
Normally, to display a browse window, you must create a
ListCfg variable, set this variable as desired using the functions
described in the last section, and populate a data variable.
However, if you want to display the contents of a file, you can
skip this whole process or just call the following procedure:
RunBrowseFile(Fname:PathStr;Tit:StrScreen);
Displays the specified file in a list window with the
specified title.
If the file cannot be displayed, Gold sets an error in
GOLDLIST. Always call LastListError to check whether the call to
RunBrowseFile was successful.
Run the demo file DEMBRS1.PAS to see RunBrowseFile in action.
The RunBrowseFile procedure provides a quick and dirty way to
browse a file. You can set the window dimensions prior to calling
the display procedure by accessing the ListVars elements WX1, WY1,
WX2, WY2, and WinStyle. If you want more control over the display
format, you should create a ListCfg variable, populate a DLL or SLL
with the file contents, and use the RunBrowse procedure discussed
below. The demo file DEMBRS2.PAS illustrates this technique.
General Browsing
You can browse the contents of a string array, a single linked
list, a double linked list or a custom data source. To do so, you
must create a variable of type ListCfg, initialize the variable
with InitListCfg and then set the variable using the Listxxx
functions described in the last few sections. (If you have been
User Guide surfing and are reading this section without reading the
earlier material in this chapter, catch a wave to the beginning of
the chapter!)
Having set the ListCfg variable to meet your needs, just call
RunBrowse as follows:
RunBrowse(var ListDetails: ListCfg;Tit:StrScreen);
Displays the data identified in ListDetails in a browse window.
Listed below is an extract from DEMBRS3.PAS which displays the
contents of an SLL in a window:
InitSLLStr(SLL);
SLLSetActiveList(SLL);
PopulateTheList;
InitListCfg(Settings);
ListAssignSLL(Settings,SLL);
ListSetWin(Settings,28,3,52,22,1);
CursorOff;
RunBrowse(Settings,' Browsing ');
SLLDestroy;
ResetStartUpMode;
Displaying List Windows
Having read this far (you did read this far, right?), you know
all there is to know about displaying lists in a window. To recap,
initialize a ListCfg variable, assign a data source, and call
RunList as follows:
RunList(var ListDetails: ListCfg;Tit:StrScreen);
Displays the data identified in ListDetails in a list window.
Back on page 15-3 there is a listing of DEMLS1.PAS which shows
how easy it is to create and display a list.
Determining the Highlighted Pick
The ListCfg variable includes the field ActiveNode, which is
of type longint. This variable always reflects the number of the
node which contains the highlight bar.
Controlling List Display Characters and Hotkeys
The ListVars variable includes the following three fields
which control characters used to indicate the higlighted pick
(ListLeft and ListRight) and tagged items (ListTag):
ListLeft: string[1];
ListRight: string[1];
ListTag: string[1];
You can customize the appearance of the list by assigning new
characters to these variables.
The keystrokes which control item tagging are stored in the
following ListVars variables:
ToggleKey: word;
TagKey: word;
UnTagKey: word;
TagAllKey: word;
UnTagAllKey: word;
Determining the User's Last Action
The ListCfg variable includes the field LastAction of type
gAction. Gold updates this variable to indicate how the user ended
the list session. For example, if the user pressed Esc it would be
set to Escaped.
Displaying Grid Windows
A grid window is designed to provide a table or columnar view
of a record and is ideal for database applications (see figure
14.1).
In most respects, the way to display a grid, using RunGrid, is
identical with the way to display a list. A grid, however, needs
additional information about the columnar aspects of the grid --
remember that a grid scrolls left and right by column rather than
by character, and Gold needs to know the logical column widths, or
tabs.
In the example, when the user presses the right cursor (or
clicks the mouse on the horizontal scroll bar), the display will
shift about 10 characters to the right so that the first visible
column is Street and the second column is City.
You inform Gold of the column widths by creating an array of
integers to represent the starting character number of each column
in the width. Figure 14.1 was generated from the demo file
DEMGRD1.PAS which included the following code to define the column
widths:
var
SourceList: SingleLL;
GridLayout: ListCfg;
GridHeading: string;
TabStops: array[1..5] of integer;
begin
TabStops[1] := 1;
TabStops[2] := 18;
TabStops[3] := 39;
TabStops[4] := 53;
TabStops[5] := 57;
...
GridAssignTabs(GridLayout,@TabStops,5);
Each element of the integer array identifies the position of
the starting character of a column. In this example, the first
column starts at character 1, the second column starts at character
18, the third column starts at character 39, and so on. When the
user scrolls rightward from the name column, Gold will display the
list starting at the 18th character.
Figure 14.1
A Grid Window
Having assigned each integer element of the array with the
appropriate column setting, the procedure GridAssignTabs is used to
instruct Gold to use the column (or tab) settings, as follows:
GridAssignTabs(var ListDetails: ListCfg; TA:pGridTabArray;
Dim:integer);
Sets the ListCfg variable ready for displaying a grid. The
integer array identifies the starting character of each column. The
third parameter identifies the total number of elements (i.e.
columns) defined in the array.
Always set the first integer in the array to a value of 1.
Grid Headings and Footers
Grid windows support up to 4 headers and 4 footers, and the
procedures, ListAssignHeader and ListAssignFooter, are used just
like list and browse titles. In fact, the use of non-scrolling
headers and footers behave exactly the same for grid windows as for
list and browse windows.
Because of a grids columnar scrolling support, however, the
scrollable titles behave a little differently. Gold needs to know
the headings (or footers) for each column. Gold searches the
strings for the split bar character "|" and uses this to separate
each columns heading. Listed below are the heading statements used
in generate the headings displayed in figure 14.1:
var
GridHeading: string;
begin
...
Gridheading := 'Name|Street|City|ST|Zip';
ListAssignHeader(GridLayout,1,GridHeading);
...
end;
This technique of embedding the column delimiter must be used
on all header and footer strings which are defined as scrollable.
Review the demo file DEMGRD1.PAS to see columns and headings
in action.
Locking Rows and Columns
One or more columns and one or more rows can be locked so that
the locked area remains visible as the user scrolls around the
grid. Use the GridSetLocks procedure to lock columns and rows as
follows:
GridSetLocks(var ListDetails: ListCfg;LCol,LRow:byte);
Locks columns and rows so that they are always visible. Lcol
identfies the number of columns (not characters) to lock, and LRow
identifies the number of rows to lock.
Listed below is an extract from DEMGRD2.PAS which uses the
column locking facility to keep the name column always visible:
procedure SetGridLayout;
{}
begin
Gridheading := 'Name|Street|City|ST|Zip';
GridFootnote := 'The name column is locked';
TabStops[1] := 1;
TabStops[2] := 18;
TabStops[3] := 39;
TabStops[4] := 53;
TabStops[5] := 57;
InitListCfg(GridLayout);
ListAssignSLL(GridLayout,SourceList);
ListAssignHeader(GridLayout,1,GridHeading);
ListAssignFooter(GridLayout,1,GridFootnote);
ListScrollFooter(GridLayout,false);
ListSetWin(GridLayout,15,5,65,15,7);
ListSetGaps(GridLayout,1,0,0,1);
GridAssignTabs(GridLayout,@TabStops,5);
GridSetLocks(GridLayout,1,0);
end; { SetGridLayout }
Determining the Highlighted Pick
The ListCfg variable includes the field ActiveNode, which is
of type longint. This variable always reflects the number of the
node which contains the highlight bar.
Controlling Grid Display Characters
The ListVars variable includes the following three fields
which control characters used to indicate the higlighted pick
(GridLeft and GridRight) and tagged items (gridTag):
GridLeft: string[1];
GridRight: string[1];
GridTag: string[1];
You can customize the appearance of the list by assigning new
characters to these variables.
The keystrokes which control item tagging are stored in the
following ListVars variables:
ToggleKey: word;
TagKey: word;
UnTagKey: word;
TagAllKey: word;
UnTagAllKey: word;
Determining the User's Last Action
The ListCfg variable includes the field LastAction of type
gAction. Gold updates this variable to indicate how the user ended
the list session. For example, if the user pressed Esc it would be
set to Escaped.
Using a Custom Data Source
In all the examples so far, you have seen how to display lists
of strings from linked lists or string arrays. You may recall that
one of the procedures ListAssignArray, ListAssignSLL or
ListAssignSLL is used to inform Gold about the data source. This
approach requires all the data to be in memory at once, and for the
majority of applications, that is not a problem.
There are, however, some situations where there is too much
data to load into memory at once. You might be trying to list
10,000 records from a database, for example. For situations such as
this, Gold allows you to assign a custom list data source using the
procedure ListAssignCustom which is defined as follows:
ListAssignCustom(var ListDetails: ListCfg; Total:longint;
CustomFunc:ListGetStrFunc);
Sets the ListCfg variable data source as custom. The procedure
is passed the total number of entries in the custom data source
along with a function which Gold will call every time it needs a
string from the custom source.
Every time Gold needs to display a string in a browse, list or
grid window, the CustomFunc function will be called. For a function
to be eligible as a custom list function it must adhere to the
following rules:
The procedure must be declared as a far procedure at the root
level. Refer to the section Understanding Hooks in Chapter 3
for further information.
The function must be declared with four passed parameters.
The first parameter is a pointer, and the last three
parameters are longints.
The following procedure declaration follows these rules:
{$F+}
function GetStrfromDB(P:pointer; Element,Start,Finish:
longint): string;
{}
begin
....
end; { GetStrfromDB }
{$F-}
When the procedure is called Gold actually passes a pointer to
the ListCfg variable as the first parameter. In most situations you
will not need to take advantage of this parameter. The second
parameter is the node or item number for which Gold needs the
string. The third and fourth parameters represent the starting and
ending character positions of the (sub) string which will be
visible.
In the case of a database list, the custom function would load
the database record, access the data in the fields, and then return
the requested sub-string. Review the demo file DEMGRD3.PAS to see
this technique in action.
Using Hooks to Fine Tune Lists
Even with all this flexibility built into the list facility,
there may still be occasions when you want to add some custom
functionality. As always, Gold has a set of hooks where you can
fine tune the behavior of the application.
Gold provides four different hooks for customizing browse,
list and grid windows.
The Character Hook
A character hook is a procedure which is called every time a
key is pressed or a mouse button is clicked while a list window has
focus. The hooked procedure is called before the key is processed
by Gold. The hook is particularly useful for trapping special keys
like F1 for help, or Alt-S to search.
All you have to do is create a procedure following some
specific rules, and then call the ListAssignCharHook procedure to
instruct Gold to call your procedure every time a key is pressed.
For a procedure to be eligible as a character hook it must
adhere to the following rules:
The procedure must be declared as a far procedure at the root
level. Refer to the section Understanding Hooks in Chapter 3
for further information.
The procedure must be declared with one variable parameter of
type word, and two variable parameters of type byte. These
parameters identify the user input, i.e. the Key, X and Y.
The following procedure declaration follows these rules:
{$F+}
procedure MyCharHook(var Code:word;var X,Y:byte);
begin
{some code}
end; {MyCharHook}
{$F-}
The following procedure is then called to instruct Gold to
call your procedure after each input:
ListAssignCharHook(var ListDetails: ListCfg; Proc:KeyPressedHook);
Instructs Gold to call the specified procedure before
processing each user input to a list window.
If, subsequently, you want to remove the character hook,
execute the following procedure:
ListRemoveCharHook(var ListDetails:ListCfg);
Removes a list character which was previously assigned with
ListAssignCharHook.
The Hind Hook
A list hind hook is similar to a character hook, except the
hook is called after an input has been processed by Gold. If you
want to write some additional information to the screen based on
the active list item, you should take advantage of the hind hook.
For a procedure to be eligible as a hind hook it must adhere
to the following rules:
The procedure must be declared as a far procedure at the root
level. Refer to the section Understanding Hooks in Chapter 3
for further information.
The procedure must be declared with one parameter of type
ListCfgPtr.
The following procedure declaration follows these rules:
{$F+}
procedure MyHineyHook(ListDetailsPtr:ListCfgPtr);
begin
{some code}
end; {MyHineyHook}
{$F-}
The following procedure is then called to instruct Gold to
call your procedure after each input:
ListAssignHindHook(var ListDetails: ListCfg; Proc:ListHindHook);
Instructs Gold to call the specified procedure after
processing each user input to a list window, and once when the
window is first displayed.
The variable parameter which is passed to the procedure is
actually a pointer to the ListCfg variable which is being used by
the list. You can de-reference the pointer to access the variable,
for example:
Total := ListDetails^.TotalNodes
If, subsequently, you want to remove the hind hook, execute
the following procedure:
ListRemoveHindHook(var ListDetails:ListCfg);
Removes a list hind which was previously assigned with
ListAssignHindHook.
The Color Hook
The color hook provides a really easy way to go beyond the
standard two colors supported by the primary list code. For
example, you might want every tenth item in a list to be displayed
in a different color, or all items with a quantity field greater
than 5000 to be displayed in a different color.
A color hook is called every time Gold wants to display a line
of text in a browse, list or grid window. For a procedure to be
eligible as a color hook it must adhere to the following rules:
The procedure must be declared as a far procedure at the root
level. Refer to the section Understanding Hooks in Chapter 3
for further information.
The procedure must be declared with three parameters. The
first parameter is a longint which indicates the node or item
number of the item that is about to be written to the window.
The second parameter is a boolean which will be set to TRUE if
the pick is the highlighted pick. The third parameter is a
variable parameter of type byte which represents the default
color that will be used -- this parameter should be updated by
the hook if a custom color is to be used.
The following procedure declaration follows these rules:
{$F+}
procedure MyColorHook(Pick:longint;Hi:boolean;
var Attr:byte);
begin
{some code}
end; {MyColorHook}
{$F-}
The following procedure is then called to instruct Gold to
call your procedure after each input:
ListAssignColorHook(var ListDetails: ListCfg; Proc:ListColorHook);
Instructs Gold to call the specified procedure before writing
the item to the list window. The hook can modify the item's display
color.
If, subsequently, you want to remove the color hook, execute
the following procedure:
ListRemoveColorHook(var ListDetails:ListCfg);
Removes a list color which was previously assigned with
ListAssignSelectHook.
The Selection Hook
A selection hook is called every time the user takes an action
which might be construed as the conclusion of the list session.
Specifically, a list selection hook is called when the user clicks
on the close icon, double clicks on a list item, presses Esc or
presses Enter.
By default, Gold will end the input session and close the list
window when any of these actions are taken by the user. In some
situations, however, you may want to override this default behavior
using a selection hook.
For a procedure to be eligible as a list selection hook it
must adhere to the following rules:
The procedure must be declared as a far procedure at the root
level. Refer to the section Understanding Hooks in Chapter 3
for further information.
The procedure must be declared with one parameter of type
ListCfgPtr.
The following procedure declaration follows these rules:
{$F+}
function MySelectHook(var Listdetails):gAction;begin
{some code}
end; {MySelectHook}
{$F-}
The following procedure is then called to instruct Gold to
call your procedure after each input:
ListAssignSelectHook(var ListDetails: ListCfg;
Proc:ListSelectHook);
Instructs Gold to call the specified procedure when the user
selects a list item by pressing Enter or double clicking on the
item, or when the user tries to escape by pressing Esc or clicking
on the window's close icon.
The variable parameter which is passed to the procedure is
actually a pointer to the ListCfg variable which is being used by
the list. You can dereference the pointer to access the variable,
for example:
Total := ListDetails^.TotalNodes
The function returns a value of type gAction (declared in
GOLDIO) which indicates how Gold should proceed. For example, an
action code of Refresh will instruct Gold to repaint the window's
client area, and an action code of Finished will instruct Gold to
close the list window.
If, subsequently, you want to remove the select hook, execute
the following procedure:
ListRemoveSelectHook(var ListDetails:ListCfg);
Removes a list selection hook which was previously assigned
with ListAssignSelectHook, and instructs Gold to use the default
hook.
The demo file DEMGRD4.PAS takes advantage of the selection
hook to add a record editor to a database browser. Check it out!
Launching Windows on the Desktop
The three primary functions RunBrowse, RunList and RunGrid
have the following counterparts for displaying windows on a desktop
application:
LaunchBrowse(var ListDetails: ListCfg;Tit:StrScreen;
CloseProc:ListCloseProc):byte;
Launches a browser for viewing the contents of an array or
linked list. The function returns the number (or handle) of the
newly created window.
LaunchList(var ListDetails: ListCfg;Tit:StrScreen;
CloseProc:ListCloseProc): byte;
Adds a list window to the desktop. The function returns the
number (or handle) of the newly created window.
LaunchGrid(var ListDetails: ListCfg;Tit:StrScreen;
CloseProc:ListCloseProc): byte;
Adds a grid window to the desktop. The function returns the
number (or handle) of the newly created window.
Like their Run counterparts, the Launch functions are passed a
ListCfg variable and a title. Additionally, the Launch functions
are passed a close function as a third parameter. This close
function is called whenever the user tries to close the window on
the desktop, and it provides you with an opportunity to do any
housekeeping (such as disposing of linked lists) before the window
is closed.
For a function to be eligible as a list close hook it must
adhere to the following rules:
The function must be declared as a far function at the root
level. Refer to the section Understanding Hooks in Chapter 3
for further information.
The function must be declared with one parameter of type
ListCfgPtr, and one integer. The function must return a
boolean value.
The following procedure declaration follows these rules:
{$F+}
function GoodbyeList(var LDP: ListCfgPtr; Handle:integer):
boolean;
{}
begin
PopUpSetActive(ListMenu,201,true);
SLLDestroy;
GoodbyeList := true;
end; { GoodbyeList }
{$F-}
If the function returns false, the window will not be closed.
The first parameter passed to the function is a pointer to the
ListCfg variable used to display the list. You can dereference this
pointer to access the variable, for example:
Total := ListDetails^.ActiveNode
The demo file DEMDESK5.PAS shows the LaunchList function in action.
Handling Errors
The list displaying functions and the header and footer
assignment functions have the potential to fail. Be sure to check
the error code by calling the LastListError and LastGridError
functions.